/*
 * Digital Audio Mobile - A multi track studio for Windows Mobile
 * Copyright (C) 2008 David Olsson
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "AudioBuffer.h"
#include "Dialog.h"
#include "Segment.h"
#include "WaveFile.h"

Segment::Segment(const MusicTime &pos) throw(): m_pos(pos), m_wavFile(0), m_file(0), m_buffer(0) {
}

Segment::~Segment() {
    if(m_buffer != 0) {
        delete(m_buffer);
    }
    if(m_file != 0) {
        delete(m_file);
    }
    if(m_wavFile != 0) {
        delete[](m_wavFile);
    }
}

void Segment::unlink() throw() {
    if(m_file != 0) {
        m_file->unlink();
        m_file = 0;
    }
    delete(this);
}

void Segment::setPosition(const MusicTime &pos) throw() {
    m_pos = pos;
}

void Segment::setSource(const TCHAR *wavFile) throw() {
    if(m_wavFile != 0) {
        delete[](m_wavFile);
        m_wavFile = 0;
    }
    if(m_file != 0) {
        delete(m_file);
        m_file = 0;
    }
    if(m_buffer != 0) {
        delete(m_buffer);
        m_buffer = 0;
    }

    m_wavFile = new TCHAR[_tcslen(wavFile) + 1];
    _tcscpy(m_wavFile, wavFile);

    openSourceFile();
}

void Segment::setFileLength(const MusicTime &length) throw() {
    m_length = length;
}

void Segment::setFileOffset(const MusicTime &offset) throw() {
    m_offset = offset;
}

void Segment::superPosition(AudioBuffer *buffer, const MusicTime &bufferStart) const throw() {
    if(m_file != 0) {
        MusicTime bufferEnd = bufferStart + MusicTime(buffer->numSamples(), buffer->samplesPerSecond());
        MusicTime end = m_pos + m_length;
        if((m_pos >= bufferStart && m_pos < bufferEnd) || (end >= bufferStart && end < bufferEnd) || (bufferStart >= m_pos && bufferStart < end) || (bufferEnd >= m_pos && bufferEnd < end)) {
            if(m_buffer == 0 || m_buffer->numSamples() < buffer->numSamples()) {
                if(m_buffer == 0) {
                    delete(m_buffer);
                }
                m_buffer = new AudioBuffer(buffer->numSamples(), m_file->numChannels(), m_file->samplesPerSecond(), m_file->bytesPerSample());
            }

            readDataIntoBuffer(bufferStart);
            buffer->superPosition(*m_buffer);
        }
    }
}

void Segment::paint(HDC hDc, HBRUSH hBrush, const RECT &rect, const MusicTime &viewStart, const MusicTime &viewEnd) const throw() {
    RECT segRect = rect;
    segRect.left = ((rect.right - rect.left) * (m_pos - viewStart).toMilliseconds()) / (viewEnd - viewStart).toMilliseconds();
    segRect.right = ((rect.right - rect.left) * ((m_pos + m_length) - viewStart).toMilliseconds()) / (viewEnd - viewStart).toMilliseconds();
    if((rect.bottom - rect.top) >= Dialog::heightToPixels(6)) {
        segRect.top += Dialog::heightToPixels(2);
        segRect.bottom -= Dialog::heightToPixels(2);
    }
    FillRect(hDc, &segRect, hBrush);

    MoveToEx(hDc, segRect.left, segRect.top, 0);
    LineTo(hDc, segRect.right, segRect.top);
    LineTo(hDc, segRect.right, segRect.bottom);
    LineTo(hDc, segRect.left, segRect.bottom);
    LineTo(hDc, segRect.left, segRect.top);
}

void Segment::openSourceFile() const throw() {
    ASSERT(m_file == 0);

    if ((m_file = WaveFile::open(m_wavFile)) != 0) {
        if(m_length == MusicTime()) {
            m_length = m_file->length();
        }
    }
}

void Segment::readDataIntoBuffer(const MusicTime &time) const throw() {
    m_buffer->clear();
    if(time < m_pos) {
        MusicTime offset = m_pos - time; // The offset into the buffer (silence first, the the segment's audio).
        unsigned int bufferOffset = offset.toSamples(m_buffer->samplesPerSecond()) * m_buffer->bytesPerSample() * m_buffer->numChannels();
        m_file->read(static_cast<unsigned char *>(m_buffer->buffer()) + bufferOffset, m_buffer->bufferSize() - bufferOffset, 0);
    }
    else {
        MusicTime offset = time - m_pos; // The offset into the wave file (skip the beginning of the file).
        unsigned int fileOffset = offset.toSamples(m_file->samplesPerSecond());
        m_file->read(m_buffer->buffer(), m_buffer->bufferSize(), fileOffset);
    }
}
